
#include <olectl.h>
#include <atlbase.h>
#include <atlwin.h>

enum ActiveXState
{ 
    Passive         = 0,    // Not loaded
    Loaded          = 1,    // Loaded, but no server   [ocx created] 
    Running         = 2,    // Server running, invisible [depersisted] 
    InPlaceActive   = 4,    // Server in-place active [visible]
    UIActive        = 8,    // Server is UI active [ready to accept input] 
    Open            = 16    // Server is opened for editing [not used]
};

const int HMperInch = 2540;
static int logPixelsX = -1;
static int logPixelsY = -1;

class ActiveXSite :
        IOleControlSite,
        IOleClientSite,
        IOleInPlaceSite, 
        IPropertyNotifySink
{ 
public:

    static int Pix2HM(int pix, int logP)
    { 
        return (HMperInch * pix + (logP >> 1)) / logP; 
    }

    static int HM2Pix(int hm, int logP)
    {
        return (logP * hm + HMperInch / 2) / HMperInch;
    } 

        ActiveXSite(ActiveXHost host)
        {
            _host = host; 
        }
 
        // IOleControlSite 
        int OnControlInfoChanged() 
        {
            return S_OK; 
        }

        int LockInPlaceActive(int fLock)
        { 
            return E_NOTIMPL;
        } 
 
        int GetExtendedControl(out object ppDisp)
        { 
            ppDisp = null;
            return E_NOTIMPL;
        }
 
        int TransformCoords(POINT pPtlHimetric, POINTF pPtfContainer, int dwFlags)
        { 
            if ((dwFlags & XFORMCOORDS_HIMETRICTOCONTAINER)  != 0) { 
                if ((dwFlags & XFORMCOORDS_SIZE) != 0) {
                    pPtfContainer.x = (float)ActiveXHelper.HM2Pix(pPtlHimetric.x, ActiveXHelper.LogPixelsX); 
                    pPtfContainer.y = (float)ActiveXHelper.HM2Pix(pPtlHimetric.y, ActiveXHelper.LogPixelsY);
                }
                else if ((dwFlags & XFORMCOORDS_POSITION) != 0) {
                    pPtfContainer.x = (float)ActiveXHelper.HM2Pix(pPtlHimetric.x, ActiveXHelper.LogPixelsX); 
                    pPtfContainer.y = (float)ActiveXHelper.HM2Pix(pPtlHimetric.y, ActiveXHelper.LogPixelsY);
                } 
                else { 
                    return E_INVALIDARG;
                } 
            }
            else if ((dwFlags & XFORMCOORDS_CONTAINERTOHIMETRIC) != 0) {
                if ((dwFlags & XFORMCOORDS_SIZE) != 0) {
                    pPtlHimetric.x = Pix2HM((int)pPtfContainer.x, ActiveXHelper.LogPixelsX); 
                    pPtlHimetric.y = Pix2HM((int)pPtfContainer.y, ActiveXHelper.LogPixelsY);
                } 
                else if ((dwFlags & XFORMCOORDS_POSITION) != 0) { 
                    pPtlHimetric.x = ActiveXHelper.Pix2HM((int)pPtfContainer.x, ActiveXHelper.LogPixelsX);
                    pPtlHimetric.y = ActiveXHelper.Pix2HM((int)pPtfContainer.y, ActiveXHelper.LogPixelsY); 
                }
                else {
                    return NativeMethods.E_INVALIDARG;
                } 
            }
            else { 
                return NativeMethods.E_INVALIDARG; 
            }
 
            return NativeMethods.S_OK;
        }

        /// <internalonly/> 
        int TranslateAccelerator(MSG pMsg, int grfModifiers)
        { 
            // This is called by IOleInPlaceActiveObject::TranslateAccelerator.
            // returning S_FALSE means we don't process the messages. Let the webbrowser control handle it. 
            return NativeMethods.S_FALSE;
        }

        int OnFocus(int fGotFocus) 
        {
            return S_OK; 
        } 

        int ShowPropertyFrame() 
        {
            return E_NOTIMPL;
        }
 
        // IOleClientSite

        int SaveObject()
        { 
            return E_NOTIMPL;
        } 
 
        int GetMoniker(int dwAssign, int dwWhichMoniker, out Object moniker)
        { 
            moniker = null;
            return E_NOTIMPL;
        }
 
        int GetContainer(out UnsafeNativeMethods.IOleContainer container) 
        {
            container = GetHost()->Container;
            return NativeMethods.S_OK;
        } 

        int ShowObject() 
        {
            if ( HostState >= ActiveXHelper.ActiveXState.InPlaceActive)
            {
                IntPtr hwnd; 
                if (NativeMethods.Succeeded(GetHost()->ActiveXInPlaceObject.GetWindow(out hwnd)))
                { 
                    if (GetHost()->ControlHandle.Handle != hwnd) 
                    {
                        if (hwnd != IntPtr.Zero) 
                        {
                            GetHost()->AttachWindow(hwnd);
                            this.OnActiveXRectChange(GetHost()->Bounds);
                        } 
                    }
                } 
                else if (GetHost()->ActiveXInPlaceObject is UnsafeNativeMethods.IOleInPlaceObjectWindowless) 
                {
                    throw new InvalidOperationException(SR.Get(SRID.AxWindowlessControl)); 
                }
            }
            return NativeMethods.S_OK;
        } 

        int UnsafeNativeMethods.IOleClientSite.OnShowWindow(int fShow) 
        { 
            return NativeMethods.S_OK;
        } 

        int UnsafeNativeMethods.IOleClientSite.RequestNewObjectLayout()
        {
            return NativeMethods.E_NOTIMPL; 
        }
 
        #endregion IOleClientSite 

        // 
        // IOleInPlaceSite methods:
        //
        suic::Handle GetWindow() 
        {
            try
            {
                return 0; 
            }
            catch (...) 
            {
            }
        }

        int ContextSensitiveHelp(int fEnterMode) 
        {
            return E_NOTIMPL; 
        } 

        int CanInPlaceActivate() 
        {
            return S_OK;
        }
 
        int OnInPlaceActivate()
        { 
            HostState = ActiveXHelper.ActiveXState.InPlaceActive;

            if (!HostBounds.IsEmpty)
            { 
                this.OnActiveXRectChange(HostBounds);
            }

            return S_OK;
        } 

        int OnUIActivate()
        {
            HostState = ActiveXHelper.ActiveXState.UIActive;
            GetHost()->Container.OnUIActivate(this.Host); 

            return S_OK;
        } 
 
        int GetWindowContext(IOleInPlaceFrame* ppFrame, IOleInPlaceUIWindow* ppDoc,
                                             COMRECT lprcPosRect, COMRECT lprcClipRect, OLEINPLACEFRAMEINFO lpFrameInfo) 
        {
            ppDoc = null; 
            ppFrame = GetHost()->Container; 

            lprcPosRect.left = (int) GetHost()->Bounds.left; 
            lprcPosRect.top =  (int) GetHost()->Bounds.top;
            lprcPosRect.right = (int) GetHost()->Bounds.right;
            lprcPosRect.bottom = (int) GetHost()->Bounds.bottom;
 
            lprcClipRect = GetHost()->Bounds;
            if (lpFrameInfo != null) 
            { 
                lpFrameInfo.cb = (uint)Marshal.SizeOf(typeof(NativeMethods.OLEINPLACEFRAMEINFO));
                lpFrameInfo.fMDIApp = false; 
                lpFrameInfo.hAccel = IntPtr.Zero;
                lpFrameInfo.cAccelEntries = 0;
                lpFrameInfo.hwndFrame = GetHost()->ParentHandle.Handle;
            } 

            return NativeMethods.S_OK; 
        } 

        int Scroll(NativeMethods.SIZE scrollExtant) 
        {
            return S_FALSE;
        }

        int OnUIDeactivate(int fUndoable) 
        {
            GetHost()->Container.OnUIDeactivate(this.Host);
            if ( HostState > ActiveXHelper.ActiveXState.InPlaceActive)
            { 
                HostState = ActiveXHelper.ActiveXState.InPlaceActive;
            } 

            return S_OK; 
        }

        int OnInPlaceDeactivate()
        { 
            if (HostState == ActiveXHelper.ActiveXState.UIActive) 
            {
                ((UnsafeNativeMethods.IOleInPlaceSite)this).OnUIDeactivate(0); 
            }

            GetHost()->Container.OnInPlaceDeactivate(this.Host);
            HostState = ActiveXHelper.ActiveXState.Running; 

            return S_OK;
        } 
 
        int DiscardUndoState()
        { 
            return S_OK;
        }

        int DeactivateAndUndo()
        { 
            return GetHost()->ActiveXInPlaceObject()->UIDeactivate();
        }

        int OnPosRectChange(COMRECT lprcPosRect) 
        {
            return OnActiveXRectChange(lprcPosRect); 
        } 

        ActiveXHelper.ActiveXState HostState
        {
            [SecurityCritical, SecurityTreatAsSafe ]
            get 
            {
                return GetHost()->ActiveXState ; 
            } 
            [SecurityCritical, SecurityTreatAsSafe ]
            set 
            {
                GetHost()->ActiveXState = value ;
            }
        } 
 
        //
        // IPropertyNotifySink methods:
        //
        void OnChanged(int dispid)
        {
            try 
            {
                OnPropertyChanged(dispid); 
            } 
            catch (...)
            { 
            }
            finally 
            {
                //GetHost()->NoComponentChangeEvents--; 
            } 
        }
 
        int OnRequestEdit(int dispid)
        {
            return S_OK;
        } 

        ActiveXHost GetHost() const
        {
            return _host;
        } 
       
        int OnActiveXRectChange(COMRECT lprcPosRect)
        { 
            if (GetHost()->ActiveXInPlaceObject != null)
            {
                GetHost()->ActiveXInPlaceObject.SetObjectRects(
                        lprcPosRect, 
                        lprcPosRect); //Same clip rect
 
                GetHost()->Bounds = lprcPosRect; 
            }
 
            return S_OK;
        }

        ActiveXHost* _host;
        //ConnectionPointCookie _connectionPoint; 
    }
} 
